#ifndef COMPLEX
#define COMPLEX

class complex;              // 分号，类的声明
complex& __doapl(complex* , const complex&);
complex& __doami(complex* , const complex&);
complex& __doaml(complex* , const complex&);

class complex{
public:
    // 这里用初始化效率更高，因此不使用等于号
    // complex(double r = 0, double i = 0) :  re = r, im = i {};
    complex(double r = 0, double i = 0) :  re(r), im(i) {};

    // 操作函数
    // 操作符重载方式一：成员函数
    complex& operator += (const complex& input);
    complex& operator -= (const complex& input);
    complex& operator *= (const complex& input);
    complex& operator /= (const complex& input);

    // 取值函数
    double real() const { return re; }
    double imag() const { return im; }
private:
    double re, im;          // 实部

    // 第一个形参传指针原因：后面会使用this指针
    friend complex& __doapl(complex* , const complex&);
    friend complex& __doami(complex* , const complex&);
    friend complex& __doaml(complex* , const complex&);
};

inline complex& __doapl(complex* ths, const complex& second) {
    ths->re += second.re;
    ths->im += second.im;
    return *ths;
}

inline complex& complex::operator += (const complex& input) {
    return __doapl(this, input);
}

inline complex& __doami(complex* ths, const complex& second) {
    ths->re -= second.re;
    ths->im -= second.im;
    return *ths;
} 

inline complex& complex::operator -= (const complex& input) {
    return __doami(this, input);
}

inline complex& __doaml(complex* ths, const complex& second) {
    double num = ths->re * second.re - ths->im * second.im;
    ths->im = ths->re * second.im + ths->im * second.re;
    ths->re = num;
    return *ths;
}

inline complex& complex::operator *= (const complex& input) {
    return __doaml(this, input);
}

// 操作符重载方法2：非成员函数
// 加减乘除
// 局部值不传引用
inline complex operator + (const complex& x, const complex& y) {
    return complex(x.real() + y.real(), x.imag() + y.imag());
}

inline complex operator + (const complex& x, const double y) {
    return complex(x.real() + y, x.imag());
}

inline complex operator + (const double x, const complex& y) {
    return complex(x + y.real(), y.imag());
}

inline complex operator - (const complex& x, const complex& y) {
    return complex(x.real() - y.real(), x.imag() - y.imag());
}

inline complex operator - (const double x, const complex& y) {
    return complex(x - y.real(), - y.imag());
}

inline complex operator - (const complex& x, const double y) {
    return complex(x.real() - y, x.imag());
}

inline complex operator * (const complex& x, const complex& y) {
    return complex(x.real() * y.real() - x.imag() * y.imag(), x.real() * y.imag() + x.imag() * y.real());
}

inline complex operator * (const double x, const complex& y) {
    return complex(x * y.real(), x * y.imag());
}

inline complex operator * (const complex& x, const double y) {
    return complex(x.real() * y, x.imag() * y);
}

inline complex operator / (const complex& x, const double y) {
    return complex(x.real() / y, x.imag() / y);
}

inline complex operator + (const complex& x) {
    return x;
}

inline complex operator - (const complex& x) {
    return complex(-x.real(), -x.real());
}

inline bool operator == (const complex& x, const complex& y) {
    return (x.real() == y.real() && x.imag() == y.imag());
}

inline bool operator == (const complex& x, const double y) {
    return (x.real() == y && x.imag() == 0);
}

inline bool operator == (const double x, const complex& y) {
    return (x == y.real() && y.imag() == 0);
}


inline bool operator != (const complex& x, const complex& y) {
    return (x.real() != y.real() || x.imag() != y.imag());
}

inline bool operator != (const complex& x, const double y) {
    return (x.real() != y && x.imag() != 0);
}

inline bool operator != (const double x, const complex& y) {
    return (x != y.real() || y.imag() != 0);
}

inline double norm (const complex& x) {
    return x.real() * x.real() + x.imag() + x.imag();
}

#include <cmath>

inline complex polar (double r, double t) {
    return complex (r * cos(t), r * sin(t));
}

inline complex conj (const complex& x) {
    return complex (x.real(), -x.imag());
}

#endif